#include "dumpParser.h"
#include <fstream>
#include <iostream>
#include <regex>

using namespace std;


unordered_map<string, unordered_set<string> > DumpParser::parse() {
  unordered_map<string, unordered_set<string> > result;
  std::ifstream inputFile(filename);
  if (!inputFile.is_open()) {
    std::cerr << "[error]: Unable to open file." << std::endl;
    return result;
  }

  std::string asmLine, funcName, funcTo;
  while (std::getline(inputFile, asmLine)) {
    if (getFuncStart(asmLine, funcName)) {
      continue;
    }
    if (!getFuncCall(asmLine, funcTo))
      continue;
    result[funcName].insert(funcTo);
  }
  inputFile.close();
  return result;
}
 /**
  "    f014:	ff d0                	call   *%rax"
  "jne    105a9 <main.cold+0xc9>"
  "75 ce                	jne    113f0 <main+0xe00>"
  "75 e3                	jne    116c0 <main>"
  "call   fa10 <main>"
  "call   *0x2edf3(%rip)        # 41fc8 <main>"
**/
bool DumpParser::getFuncCall(const string &asmLine, string &funcName) {
  std::smatch matches;
  std::regex funcStart("(call|jz|jnz|jc|jnc|jo|jno|js|jns|jp|jnp|je|jne|jcxz|jecxz|jrcxz|ja|jnbe|jae|jnb|jb|jnae|jbe|jna|jg|jnle|jge|jnl|jl|jnge|jle)\\s+[\\S]+.*\\s+<([\\w@]+)(\\+0x.*)?>");
  if (!std::regex_search(asmLine, matches, funcStart))
    return false;

  if (matches.size() > 2)
    funcName = matches[2];

  return true;
}

/**
* 0000000000005e00 <main>:
**/
bool DumpParser::getFuncStart(const string &asmLine, string &funcName) {
  std::smatch matches;
  std::regex funcStart("\\d+\\s+<(\\w+)>:$");
  if (!std::regex_search(asmLine, matches, funcStart))
    return false;

  if (matches.size() > 1)
    funcName = matches[1];

  return true;
}
void DumpParser::print(unordered_map<string, unordered_set<string> > &result) {
  // 打印结果
  for (const auto &pair : result) {
    for (const auto &funcTo : pair.second) {
      cout << pair.first << ": " << funcTo << endl;
    }
  }
}
std::string DumpParser::demangle(const std::string& mangled_name) {
    std::string command = "c++filt \"" + mangled_name + "\"";
    std::string result;
    FILE* pipe = popen(command.c_str(), "r");
    if (!pipe) {
        std::cerr << "popen failed!" << std::endl;
        return "";
    }
    char buffer[128];
    while (!feof(pipe)) {
        if (fgets(buffer, 128, pipe) != nullptr) {
            result += buffer;
        }
    }
    pclose(pipe);
    if (result.back() == '\n')
      result.pop_back();
    return result;
}
void DumpParser::print(unordered_map<string, unordered_set<string> > &result, string &startFunc) {
  // 打印结果
  for (const auto &funcTo : result[startFunc]) {
    cout << startFunc << ": " << demangle(funcTo) << endl;
  }
}
